home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGBLER / WHIZZARD.LZH / PRSLASHO.ASM < prev    next >
Assembly Source File  |  1984-06-26  |  23KB  |  960 lines

  1. COMMENT *
  2.  
  3.                  CLUBware  (tm)
  4.  
  5.       PRSLASHO - Enhancement to the Basic Compiler Print statement
  6.                 (for routines compiled with /O option)
  7.  
  8.            Copyright 1984 Rayhawk Automation N.W. Inc
  9.                   P.O. Box 1427
  10.                   Beaverton, Oregon   97075
  11.                                           *
  12.  
  13. SCRDSEG   SEGMENT
  14.  
  15.       ASSUME  CS:SCRDSEG,DS:NOTHING,ES:NOTHING,SS:STACK
  16.  
  17. ORIG_INT10      LABEL  WORD           ; original int 10
  18.       DW      0
  19.       DW      0
  20.  
  21. ;______________________________________________________________________________
  22.  
  23. ;   Swap the code used by BASIC to print strings.  Swap must be made
  24. ;    after BASIC has been loaded and initialized its environment.  When the
  25. ;    screen is cleared INTSWAP intercepts the BASIC print statement.
  26.  
  27. ORIG_SUB      LABEL  WORD           ; original subroutine for printing
  28.       DW      0               ;  strings
  29. BASIC_SEGMENT      LABEL  WORD
  30.       DW      0
  31.  
  32. FLAG_ADDRESS      LABEL  WORD           ; address of flag used to determine
  33.       DW      0               ;  target of i/o for basic
  34.  
  35.  
  36. SWAPFLAG      LABEL  BYTE
  37.           DB  00000000b        ; flag controlling swapping of subs
  38. TRAP_CHAR      EQU 00000001b        ; trap next character to be printed
  39. SECOND_TIME      EQU 00000010b        ; second character printed
  40. UNDER_DEBUG      EQU 00000100b        ; executing under debug
  41.  
  42. SCREEN_PAGE      LABEL  WORD
  43.       DW      0               ; address of current page
  44.  
  45. SCREEN_POSITION   LABEL  WORD
  46.       DW      0               ; address of screen position
  47.  
  48. BYTES_LINE      LABEL  WORD
  49.       DW      0               ; address of number of bytes per line
  50.  
  51. CHAR_ATTRIBUTE      LABEL  WORD
  52.       DW      0               ; address of attribute
  53.  
  54. CALLERS_SEG      EQU  WORD PTR [BP+4]    ; location of callers segment on stack
  55.  
  56. STRING_CALLER      EQU  WORD PTR [BP+16] ; location of callers offset on stack
  57.  
  58. NUMBER_CALLER      EQU  WORD PTR [BP+26] ; location of callers offset on stack
  59.  
  60.  
  61. INTSWAP   PROC      FAR
  62.  
  63.       CMP      AX,0600h           ; clear screen request?
  64.       JNE      NOT_SCREEN_CLEAR
  65.       MOV      SWAPFLAG,TRAP_CHAR   ; try trapping the next char printed
  66.       JMP      DWORD PTR ORIG_INT10 ; pass call to BIOS
  67.  
  68.  
  69. NOT_SCREEN_CLEAR:
  70.  
  71.       TEST      SWAPFLAG,TRAP_CHAR   ; supposed to trap next char?
  72.       JZ      NOT_TRAPPED
  73.       CMP      AH,09            ; request to print a char?
  74.       JNE      NOT_TRAPPED
  75.       TEST      SWAPFLAG,SECOND_TIME ; is this the second char printed?
  76.       JNZ      DO_SWAP
  77.       OR      SWAPFLAG,SECOND_TIME ; first character has been seen
  78.  
  79. NOT_TRAPPED:
  80.       JMP      DWORD PTR ORIG_INT10 ; pass call to BIOS
  81.  
  82. DO_SWAP:
  83.       TEST      SWAPFLAG,UNDER_DEBUG
  84.       JNZ      NOT_TRAPPED
  85.       OR      SWAPFLAG,UNDER_DEBUG
  86.       PUSH      BP               ; address the stack
  87.       MOV      BP,SP
  88.       PUSH      DS
  89.       PUSH      SI
  90.       PUSH      AX
  91.  
  92.  
  93.       MOV      AX,CALLERS_SEG       ; address basic's code space
  94.       MOV      DS,AX
  95.  
  96.       MOV      SI,NUMBER_CALLER     ; load offset of intermediate caller
  97.       SUB      SI,8               ; back up to start of LOOP
  98.  
  99. ;    do we recognize this as a number being printed?
  100.  
  101.       CMP      WORD PTR DS:[SI],0AACh         ; code to print number?
  102.       JNE      MAYBE_STRING                 ; jump if so
  103.  
  104.       CMP      BYTE PTR DS:[SI+8],0EBh         ; just to make sure
  105.       JE      GET_SUB_ADDRESS
  106.       JMP      ALREADY_SAVED
  107.  
  108.  
  109. ;     see if perhaps this is a string being printed
  110.  
  111. MAYBE_STRING:
  112.       CMP      WORD PTR DS:[SI+4],0E8ACh         ; code to print string?
  113.       JNE      ALREADY_SAVED              ; jump if not
  114.  
  115.       CMP      BYTE PTR DS:[SI+8],0E2h         ; just to make sure
  116.       JNE      ALREADY_SAVED
  117.  
  118.  
  119. GET_SUB_ADDRESS:
  120.       ADD      SI,WORD PTR DS:[SI+6]          ; load offset of sub
  121.       ADD      SI,8
  122.  
  123. ;   have we already taken over this subroutine once before?
  124.  
  125.       CMP      WORD PTR DS:[SI+1],OFFSET PRINTER
  126.       JE      ALREADY_SAVED
  127.  
  128.       CMP      BYTE PTR DS:[SI],9Ah             ; opcode is far call?
  129.       JE      SECOND_COPY
  130.  
  131.  
  132. ;   track down the data we need to perform screen output
  133.  
  134.       PUSH      SI
  135.       PUSH      AX
  136.  
  137.       MOV      AX,WORD PTR DS:[SI+3]          ; load offset of flag
  138.       MOV      FLAG_ADDRESS,AX             ; save it for later
  139.  
  140.       ADD      SI,WORD PTR DS:[SI+11]  ; code where screen position is used
  141.       ADD      SI,60h
  142.       ADD      SI,WORD PTR DS:[SI]      ; code where screen position is used
  143.       ADD      SI,8
  144.       MOV      AX,WORD PTR DS:[SI]
  145.       MOV      SCREEN_POSITION,AX
  146.  
  147.       ADD      SI,23h           ; code where bytes/line is used
  148.       MOV      AX,WORD PTR DS:[SI]
  149.       MOV      BYTES_LINE,AX
  150.  
  151.       ADD      SI,5Eh           ; code where attribute is used
  152.       MOV      AX,WORD PTR DS:[SI]
  153.       MOV      CHAR_ATTRIBUTE,AX
  154.  
  155.       SUB      SI,5               ; back up to where new position is called
  156.       ADD      SI,WORD PTR DS:[SI]  ; add offset of subroutine
  157.  
  158.       ADD      SI,11            ; forward to where next sub is called
  159.       ADD      SI,WORD PTR DS:[SI]  ; add offset of subroutine
  160.  
  161.       ADD      SI,5               ; code where page is used
  162.       MOV      AX,WORD PTR DS:[SI]
  163.       MOV      SCREEN_PAGE,AX
  164.  
  165.  
  166.       POP      AX
  167.       POP      SI
  168.  
  169.  
  170. ;   replace the original code with a call to PRINTER to intercept prints
  171.  
  172. SECOND_COPY:
  173.       MOV      BYTE PTR DS:[SI],9Ah              ; opcode is far call
  174.       MOV      WORD PTR DS:[SI+1],OFFSET PRINTER   ; target for call
  175.       MOV      WORD PTR DS:[SI+3],SEG    PRINTER
  176.       MOV      BASIC_SEGMENT,AX              ; save basic's code seg
  177.       ADD      SI,5                      ; walk past call
  178.       MOV      ORIG_SUB,SI                  ; save original sub addr
  179.  
  180. ALREADY_SAVED:
  181.       MOV      SWAPFLAG,0                  ; clear the swap flag
  182.  
  183.       POP      AX
  184.       POP      SI
  185.       POP      DS
  186.       POP      BP
  187.       JMP      DWORD PTR ORIG_INT10 ; pass clear screen to BIOS now
  188.  
  189.  
  190.  
  191. INTSWAP   ENDP
  192.  
  193. ;______________________________________________________________________________
  194.  
  195. COMMENT * PRINTER prints a character string on the screen starting
  196.           at the current cursor position.  After the string is
  197.           written to the screen the cursor position is updated
  198.           to just after the string.
  199.  
  200.       To use this routine, a clear screen must occur
  201.           to swap in the PRINTER routine for basic.
  202.  
  203.  
  204.       The PRSLASHO module will take over the INT 10h and make
  205.           this module permanently resident.  The user from inside
  206.           his BASIC program will clear the screen with a CLS
  207.           which will perform the vector swap.
  208.  
  209.       Algorithm:
  210.  
  211.       On entry
  212.           DS:[SI] points to string to write
  213.           CX      contains count of characters to write
  214.           BX      may contain count of blanks to write
  215.           SCREEN_PAGE      contains the page to which we write
  216.           CHAR_ATTRIBUTE  contains the attribute for the text
  217.           SCREEN_POSITION contains the current screen location and must
  218.                    be updated after print is complete
  219.  
  220.  
  221.                                           *
  222. ;______________________________________________________________________________
  223.  
  224. ;  Local data addressable through CS register
  225.  
  226.  
  227. CHAR_COUNT      LABEL  WORD
  228.       DW      0
  229.  
  230.  
  231. LINE_START      LABEL  WORD
  232.       DW      0               ;  0
  233.       DW      160               ;  1
  234.       DW      320               ;  2
  235.       DW      480               ;  3
  236.       DW      640               ;  4
  237.       DW      800               ;  5
  238.       DW      960               ;  6
  239.       DW      1120               ;  7
  240.       DW      1280               ;  8
  241.       DW      1440               ;  9
  242.  
  243.       DW      1600               ;  10
  244.       DW      1760               ;  11
  245.       DW      1920               ;  12
  246.       DW      2080               ;  13
  247.       DW      2240               ;  14
  248.       DW      2400               ;  15
  249.       DW      2560               ;  16
  250.       DW      2720               ;  17
  251.       DW      2880               ;  18
  252.       DW      3040               ;  19
  253.       DW      3200               ;  20
  254.       DW      3360               ;  21
  255.       DW      3520               ;  22
  256.       DW      3680               ;  23
  257.       DW      3840               ;  24
  258.  
  259. PAGE_START      LABEL  WORD
  260.       DW      0
  261.       DW      4000
  262.       DW      8000
  263.       DW      12000
  264.  
  265. STARTING_PAGE      LABEL  WORD
  266.       DW      0
  267.  
  268. END_OF_PAGE      LABEL  WORD
  269.       DW      0
  270.  
  271. STARTING_LINE      LABEL  WORD
  272.       DW      0
  273.  
  274. RESIDUAL      LABEL  WORD
  275.       DW      0
  276.  
  277.  
  278. LOCAL_FLAG      LABEL  BYTE
  279.           DB   00000000b
  280. JUST_BLANKS      EQU  00000001b       ; basic wants just blanks displayed
  281. ZERO_TAGGED      EQU  00000010b       ; string length unknown, tagged by 0
  282.  
  283.  
  284. ;______________________________________________________________________________
  285.  
  286. COMMENT *
  287.  
  288.    New PRINT service routine for BASIC
  289.  
  290.      Calls to routine XXXX:0C5B are rerouted to this piece of code
  291.      These calls come from several places within the BASIC rutime library
  292.      We service calls from four locations:  - calls to display a string
  293.                         - calls to expand tabs
  294.                         - calls to blank pad fields
  295.                         - calls to display a number
  296.      Calls from anywhere else are serviced by the original basic code.
  297.      The four labels corresponding to the four types of calls we service
  298.      are  STRING_IO
  299.       REPEAT_BLANKS
  300.       NUMBER_STRING
  301.       PAD_FIELD
  302.      The code labeled BASIC_IO passes the interrupt back to the basic code
  303.      for service.
  304.                                           *
  305.  
  306.  
  307. PRINTER   PROC      FAR
  308.  
  309.       PUSH      BP
  310.       PUSH      ES
  311.       MOV      BP,BASIC_SEGMENT
  312.       MOV      ES,BP
  313.  
  314.       MOV      LOCAL_FLAG,0           ; clear the flag for string i/o
  315.  
  316.  
  317. ;    check context for simple text to screen or possibly something
  318. ;      more involved that basic should handle
  319.  
  320.       MOV      BP,FLAG_ADDRESS
  321.       CMP      WORD PTR DS:[BP],0
  322.       JNE      BASIC_IO
  323.  
  324.       MOV      BP,BYTES_LINE
  325.       CMP      BYTE PTR DS:[BP],50h ; 80 bytes per line?
  326.       JNE      BASIC_IO
  327.  
  328.       MOV      BP,SP            ; address the stack
  329.  
  330.       MOV      BP,WORD PTR [BP+8]       ; load offset of caller
  331.  
  332.       CMP      BYTE PTR ES:[BP],0EBh    ; number to print?
  333.       JE      NUMBER_STRING
  334.  
  335.       CMP      BYTE PTR ES:[BP],04Bh    ; tab to expand?
  336.       JE      REPEAT_BLANKS
  337.  
  338.       CMP      BYTE PTR ES:[BP],0E2h    ; is this a loop instruction?
  339.       JNE      BASIC_IO
  340.       CMP      BYTE PTR ES:[BP-4],0ACh  ; is this LODSB in loop?
  341.       JE      STRING_IO
  342.       CMP      WORD PTR ES:[BP-5],20B0h ; is this MOV AL in loop?
  343.       JE      PAD_FIELD
  344.  
  345. ;    allow original service routine to perform I/O
  346.  
  347. BASIC_IO:
  348.       MOV      BP,SP
  349.       PUSH      AX
  350.       MOV      AX,WORD PTR [BP+8]
  351.       POP      AX
  352.  
  353.       POP      ES
  354.       POP      BP
  355.       ADD      SP,4               ; clear our far call from stack
  356.       PUSH      SI               ; original first two statements
  357.       MOV      SI,FLAG_ADDRESS
  358.       MOV      SI,WORD PTR DS:[SI]  ;   of the basic subroutine
  359.       JMP      DWORD PTR ORIG_SUB   ; pass control to original routine
  360.  
  361.  
  362.  
  363. ; ----------
  364.  
  365.  
  366. ;    send a number string to screen
  367. ;          string length is not known but end is tagged by a zero
  368.  
  369. NUMBER_STRING:
  370.  
  371.       PUSH      BX               ; save registers used
  372.       PUSH      DX
  373.       PUSH      DI
  374.  
  375.  
  376. ;      ...      1) store character count and mark the flag for type of i/o
  377.  
  378.       DEC      SI               ; backup to start of string
  379.       MOV      CHAR_COUNT,80        ; always less than 80 characters
  380.       OR      LOCAL_FLAG,ZERO_TAGGED
  381.       MOV      RESIDUAL,CX           ; restore original cx contents when done
  382.       JMP      SETUP_START
  383.  
  384.  
  385. ; ----------
  386.  
  387.  
  388. ;    repeated blanks sent to screen to expand a tab
  389.  
  390. REPEAT_BLANKS:
  391.  
  392.       PUSH      BX               ; save registers used
  393.       PUSH      DX
  394.       PUSH      DI
  395.  
  396.  
  397. ;      ...      1) store character count and mark the flag for type of i/o
  398.  
  399.       MOV      CHAR_COUNT,BX        ; save character count
  400.       OR      LOCAL_FLAG,JUST_BLANKS
  401.       MOV      RESIDUAL,1           ; leave one in cx register when done
  402.       JMP      SETUP_START
  403.  
  404.  
  405. ; ----------
  406.  
  407.  
  408. ;    repeated blanks sent to screen to fill a field area
  409.  
  410. PAD_FIELD:
  411.  
  412.       PUSH      BX               ; save registers used
  413.       PUSH      DX
  414.       PUSH      DI
  415.  
  416.  
  417. ;      ...      1) store character count and mark the flag for type of i/o
  418.  
  419.       MOV      CHAR_COUNT,CX        ; save character count
  420.       OR      LOCAL_FLAG,JUST_BLANKS
  421.       MOV      RESIDUAL,1           ; leave one in cx register when done
  422.       JMP      SETUP_START
  423.  
  424.  
  425. ; ----------
  426.  
  427.  
  428. ;    write the string for basic
  429.  
  430. STRING_IO:
  431.  
  432. ;      CMP      BYTE PTR DS:[06CAh],50h  ; 80 bytes per line?
  433. ;          WAS ORIGINALLY 6D0h
  434. ;      JNE      BASIC_IO
  435.  
  436.       PUSH      BX               ; save registers used,
  437.       PUSH      DX
  438.       PUSH      DI
  439.  
  440.  
  441.  
  442. ;      ...      1) backup to start of string and store character count
  443.  
  444.       DEC      SI               ; backup to start of string
  445.       MOV      CHAR_COUNT,CX        ; save character count
  446.       MOV      RESIDUAL,1           ; leave one in cx register when done
  447.  
  448.  
  449. ;      ...      2) load current page
  450.  
  451. SETUP_START:
  452.       MOV      BP,SCREEN_PAGE
  453.       MOV      BL,BYTE PTR DS:[BP]  ; load current page
  454.       SUB      BH,BH
  455.       SHL      BX,1               ; convert to a table offset
  456.       MOV      DI,PAGE_START[BX]    ; load start of page
  457.       MOV      STARTING_PAGE,DI     ; save the page
  458.       MOV      END_OF_PAGE,DI       ; save ending page pointer
  459.       ADD      END_OF_PAGE,4000
  460.  
  461.  
  462.  
  463. ;      ...      3) load current position on page
  464.  
  465.       MOV      BP,SCREEN_POSITION
  466.       MOV      DX,WORD PTR DS:[BP]  ; load current position
  467.       DEC      DH               ; basic counts from 1 instead of 0
  468.       DEC      DL               ; basic counts from 1 instead of 0
  469.       MOV      BL,DL            ; load row number
  470.       SHL      BX,1               ; two bytes per table entry
  471.       ADD      DI,LINE_START[BX]    ; add in start of line
  472.       MOV      STARTING_LINE,DI     ; store this for later
  473.  
  474.  
  475.       MOV      DL,DH            ; bring down column number
  476.       SUB      DH,DH
  477.       ADD      DI,DX            ; add in column position
  478.       ADD      DI,DX            ; account for attribute bytes
  479.  
  480.  
  481.  
  482. ;      ...      4) load attribute for string
  483.  
  484.       MOV      BP,CHAR_ATTRIBUTE
  485.       MOV      BH,BYTE PTR DS:[BP]  ; load attribute for string
  486.  
  487.  
  488.  
  489. ;      ...      5) move character count to CX for use in loop
  490.  
  491.       MOV      CX,CHAR_COUNT        ; load the character count
  492.  
  493.  
  494.  
  495. ;      ...      6) load type of crt display from 0000:463
  496.  
  497.       SUB      AX,AX            ; address system memory
  498.       MOV      ES,AX
  499.  
  500.       MOV      DX,WORD PTR ES:[463h]      ; load address of display adapter
  501.       ADD      DX,6                 ; address crt status port
  502.  
  503.  
  504. ;      ...      7) address the screen segment
  505.  
  506.       MOV      AX,0B000h           ; screen seg for monochrome card
  507.       CMP      DX,03DAh           ; is this a graphic card?
  508.       JNE      MONOCHROME
  509.  
  510.       MOV      AX,0B800h           ; load screen seg for graphic card
  511.  
  512. MONOCHROME:
  513.  
  514.       MOV      ES,AX            ; address the screen buffer
  515.  
  516.  
  517.  
  518. ;      ...      8) move string to screen while synchronizing
  519. ;              with horizontal retrace
  520.  
  521.       TEST      LOCAL_FLAG,JUST_BLANKS
  522.       JZ      DISPLAY_LOOP
  523.  
  524.       MOV      BL,20h           ; load a blank
  525. BLANK_LOOP:
  526.       CALL      DISPLAY_CHAR           ; display a line of blanks for basic
  527.       LOOP      BLANK_LOOP
  528.       JMP      UPDATE_POSITION
  529.  
  530.  
  531. DISPLAY_LOOP:
  532.       LODSB                ; load next character
  533.  
  534.       CMP      AL,20h           ; special character?
  535.       JGE      NOT_SPECIAL
  536.       CALL      SPECIAL
  537.       JZ      ANOTHER_CHAR           ; if flag set, go for another character
  538.  
  539. NOT_SPECIAL:
  540.  
  541.       MOV      BL,AL
  542.  
  543.       CLI
  544. HSYNC_WAIT1:
  545.       IN      AL,DX            ; check for horizontal retrace
  546.       TEST      AL,1
  547.       JNZ      HSYNC_WAIT1           ; wait for retrace
  548. HSYNC_WAIT2:
  549.       IN      AL,DX            ; check for horizontal retrace
  550.       TEST      AL,1
  551.       JZ      HSYNC_WAIT2           ; wait for retrace
  552.  
  553.       MOV      AX,BX
  554.       STOSW                ; store character and attribute
  555.  
  556. ANOTHER_CHAR:
  557.       STI
  558.  
  559.       CMP      DI,END_OF_PAGE
  560.       JL      NOT_SCROLLED
  561.  
  562.       MOV      AL,0Dh           ; force a carriage return and scroll
  563.       CALL      SPECIAL
  564.  
  565. NOT_SCROLLED:
  566.  
  567.       LOOP      DISPLAY_LOOP           ; repeat cx times
  568.  
  569.  
  570.  
  571. ;      ...     9) update cursor position on screen
  572.  
  573.  
  574. UPDATE_POSITION:
  575.       MOV      AX,DI
  576.       SUB      AX,STARTING_PAGE
  577.       SHR      AX,1               ; eliminate attribute bytes
  578.       SUB      DX,DX
  579.       MOV      BX,80            ; divide by bytes per line
  580.       DIV      BX               ;   quotient in AL (ROW)
  581.                        ;   remainder in DL (COLUMN)
  582.       MOV      DH,AL
  583.       MOV      BP,SCREEN_PAGE
  584.       MOV      BH,BYTE PTR DS:[BP]  ; load page number
  585.       MOV      AH,2               ; request new position
  586.       INT      10h
  587.  
  588.  
  589. ;      ...      10) update cursor position
  590.  
  591.       XCHG      DH,DL            ; basic likes this reversed
  592.       INC      DH               ; basic counts from 1 instead of 0
  593.       INC      DL               ; basic counts from 1 instead of 0
  594.       MOV      BP,SCREEN_POSITION
  595.       MOV      WORD PTR DS:[BP],DX
  596.  
  597.  
  598. ;      ...      11) leave registers in manner BASIC expects
  599.  
  600.       MOV      CX,RESIDUAL           ; let decrement instr take this to zero
  601.                        ;  inside basic
  602.       POP      DI
  603.       POP      DX
  604.  
  605.       POP      BX
  606.       POP      ES
  607.       POP      BP
  608.  
  609.  
  610.       ADD      SP,4               ; throw away offset and code segment
  611.                        ;  from our call
  612.  
  613.       POP      AX               ; throw away near call on stack
  614.       PUSH      BASIC_SEGMENT        ; and convert to a far call
  615.       PUSH      AX
  616.       RET                   ; return to basic
  617.  
  618.  
  619. PRINTER   ENDP
  620.  
  621. ;______________________________________________________________________________
  622.  
  623. ;  subroutine to handle special control characters
  624.  
  625. SPECIAL   PROC      NEAR
  626.  
  627. ; ----------
  628.  
  629.       CMP      AL,0Ah           ; line feed?
  630.       JE      NEW_LINE
  631.  
  632.  
  633. ; ----------
  634.  
  635.       CMP      AL,0Bh           ; home?
  636.       JNE      NOT_HOME
  637.       MOV      DI,STARTING_PAGE     ; start over at top of screen
  638.       MOV      STARTING_LINE,DI
  639.       SUB      AL,AL
  640.       RET
  641.  
  642. NOT_HOME:
  643.  
  644. ; ----------
  645.  
  646.       CMP      AL,0Ch           ; clear screen?
  647.       JNE      NOT_CLEAR
  648.       MOV      DI,STARTING_PAGE
  649.       MOV      STARTING_LINE,DI
  650.       MOV      AL,0               ; clear whole window
  651.       JMP      SHORT SCROLL_SCREEN
  652.  
  653.  
  654. NOT_CLEAR:
  655.  
  656. ; ----------
  657.  
  658.       CMP      AL,0Dh           ; carriage return?
  659.       JNE      NOT_CR
  660.  
  661. NEW_LINE:
  662.       MOV      DI,STARTING_LINE
  663.       ADD      DI,160
  664.       JMP      SHORT TEST_RIGHT
  665.  
  666. NOT_CR:
  667.  
  668. ; ----------
  669.  
  670.       CMP      AL,1Ch           ; move right?
  671.       JNE      NOT_RIGHT
  672.       ADD      DI,2
  673.       JMP      SHORT TEST_RIGHT
  674.  
  675. NOT_RIGHT:
  676.  
  677. ; ----------
  678.  
  679.       CMP      AL,1Dh           ; move left?
  680.       JNE      NOT_LEFT
  681.       SUB      DI,2
  682.       JMP      SHORT TEST_LEFT
  683.  
  684. NOT_LEFT:
  685.  
  686. ; ----------
  687.  
  688.       CMP      AL,1Eh           ; move up?
  689.       JNE      NOT_UP
  690.  
  691.       SUB      DI,160
  692.       JMP      SHORT TEST_LEFT
  693.  
  694. NOT_UP:
  695.  
  696. ; ----------
  697.  
  698.       CMP      AL,1Fh           ; move down?
  699.       JNE      NOT_DOWN
  700.  
  701.       ADD      DI,160
  702.       JMP      SHORT TEST_RIGHT
  703.  
  704. NOT_DOWN:
  705.       JMP      SHORT TEST_FOR_TAB
  706.  
  707. ; ----------
  708.  
  709. TEST_RIGHT:
  710.       CMP      DI,END_OF_PAGE       ; are we past line 25?
  711.       JL      VALID_RIGHT
  712.       MOV      DI,STARTING_PAGE     ; back at start of last line
  713.       ADD      DI,3840
  714.       MOV      STARTING_LINE,DI
  715.  
  716.       MOV      AL,1               ; scroll one line
  717.       JMP      SHORT SCROLL_SCREEN
  718.  
  719. VALID_RIGHT:
  720.       SUB      AL,AL
  721.       RET
  722.  
  723. ; ----------
  724.  
  725. SCROLL_SCREEN:
  726.       PUSH      CX
  727.       MOV      CX,0               ; start in upper left corner
  728.       PUSH      DX
  729.       MOV      DX,184Fh           ; end in lower right
  730.       MOV      AH,6
  731.       PUSHF                ; simulate an INT 10
  732.       CALL      DWORD PTR ORIG_INT10
  733.       POP      DX
  734.       POP      CX
  735.       SUB      AL,AL
  736.       RET
  737.  
  738. ; ----------
  739.  
  740. TEST_LEFT:
  741.       CMP      DI,STARTING_PAGE
  742.       JGE      VALID_LEFT
  743.  
  744.       MOV      DI,STARTING_PAGE
  745.  
  746. VALID_LEFT:
  747.       SUB      AL,AL
  748.       RET
  749.  
  750. ; ----------
  751.  
  752. TEST_FOR_TAB:
  753.  
  754.       CMP      AL,09h           ; tab?
  755.       JNE      NOT_TAB
  756.  
  757.       PUSH      CX
  758.       PUSH      DX
  759.       MOV      AX,DI
  760.       SUB      AX,STARTING_LINE
  761.       SHR      AX,1               ; discount attribute bytes
  762.       SUB      DX,DX
  763.       MOV      CX,8
  764.       DIV      CX
  765.       MOV      CX,8               ; tab positions are every 8 charactes
  766.       SUB      CX,DX            ; subtract off remainder
  767.       MOV      BL,' '               ; write some blanks
  768.       POP      DX
  769. TAB_LOOP:
  770.       CALL      DISPLAY_CHAR
  771.       LOOP      TAB_LOOP
  772.  
  773.       POP      CX
  774.       SUB      AL,AL
  775.       RET
  776.  
  777. NOT_TAB:
  778.  
  779. ; ----------
  780.  
  781.       CMP      AL,08h           ; backspace?
  782.       JNE      NOT_BACKSPACE
  783.  
  784.       CMP      DI,STARTING_LINE
  785.       JE      AT_START
  786.       SUB      DI,2               ; back up a space
  787.  
  788. AT_START:
  789.       MOV      BL,' '               ; write a blank
  790.       CALL      DISPLAY_CHAR
  791.  
  792.       SUB      DI,2               ; back up a space
  793.       SUB      AL,AL
  794.       RET
  795.  
  796. NOT_BACKSPACE:
  797.  
  798. ; ----------
  799.  
  800.       CMP      AL,00h           ; null?
  801.       JNE      NOT_NULL
  802.  
  803.       TEST      LOCAL_FLAG,ZERO_TAGGED  ; does this mean end of string?
  804.       JZ      NOT_NULL          ;  branch if null meaningless
  805.       MOV      CX,1               ; terminate the display loop
  806.       DEC      SI               ; backup so basic can see null too
  807.       SUB      AL,AL
  808.       RET
  809.  
  810. NOT_NULL:
  811.  
  812. ; ----------
  813.  
  814.       MOV      AH,2
  815.       SUB      AH,1               ; set flag to display the char
  816.       RET
  817.  
  818. SPECIAL   ENDP
  819.  
  820. ;______________________________________________________________________________
  821.  
  822. ;  routine to display a character in BL - used only for special characters
  823. ;     and repeated blanks - attribute is in BH
  824.  
  825.  
  826. DISPLAY_CHAR      PROC    NEAR
  827.  
  828.       CLI
  829. HSYNC_WAIT3:
  830.       IN      AL,DX            ; check for horizontal retrace
  831.       TEST      AL,1
  832.       JNZ      HSYNC_WAIT3           ; wait for retrace
  833. HSYNC_WAIT4:
  834.       IN      AL,DX            ; check for horizontal retrace
  835.       TEST      AL,1
  836.       JZ      HSYNC_WAIT4           ; wait for retrace
  837.  
  838.       MOV      AX,BX
  839.       STOSW                ; store character and attribute
  840.  
  841.       STI
  842.       RET
  843.  
  844. DISPLAY_CHAR      ENDP
  845.  
  846.  
  847. ;______________________________________________________________________________
  848.  
  849.  
  850.  
  851. LASTADDR  LABEL   BYTE
  852.  
  853. COPYRIGHT LABEL   BYTE
  854.       DB      10,13
  855.       DB  '         CLUBware  (tm)',10,13,10,13
  856.       DB  'PRSLASHO - Enhancement to the Basic Compiler Print statement'
  857.       DB      10,13
  858.       DB  '                 (for routines compiled with /O option)'
  859.       DB      10,13,10,13
  860.       DB  '         Copyright 1984 Rayhawk Automation N.W. Inc',10,13
  861.       DB  '                        P.O. Box 1427',10,13
  862.       DB  '                        Beaverton, Oregon   97075',10,13,'$'
  863.  
  864.  
  865. ;______________________________________________________________________________
  866.  
  867.  
  868. PRSLASHO  PROC      FAR
  869.  
  870.  
  871.       PUSH      DS               ; Push addr of Program Segment Prefix
  872.       SUB      AX,AX            ; Zero AX
  873.       PUSH      AX               ; Push zero onto stack
  874. ;                     (offset of INT 20 within PSP)
  875.  
  876.  
  877. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  878. ;              |                          |
  879. ;              |        take over the INT 10h         |
  880. ;              |        interrupt if not already done     |
  881. ;              |                          |
  882. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  883.  
  884.       MOV      DS,AX            ; address low memory
  885.  
  886. ;      CMP      WORD PTR DS:[40h],OFFSET INTSWAP
  887. ;      JE      ALREADY_DONE
  888.  
  889.       MOV      AX,WORD PTR DS:[40h] ; save original int10
  890.       MOV      ORIG_INT10,AX
  891.       MOV      AX,WORD PTR DS:[42h]
  892.       MOV      ORIG_INT10+2,AX
  893.  
  894.       MOV      AX,SEG PRSLASHO
  895.       MOV      DS,AX
  896.       MOV      DX,OFFSET INTSWAP    ; Load offset of interrupt service mod
  897.       MOV      AX,2510h           ; Prepare for DOS service call type 25
  898. ;                     to establish service for INT 10
  899.       INT      21h               ; Ask DOS to establish service
  900.  
  901. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  902. ;              |                          |
  903. ;              |        issue copyright message         |
  904. ;              |                          |
  905. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  906.  
  907.       MOV      DX,OFFSET COPYRIGHT
  908.       MOV      AH,9
  909.       INT      21h
  910.  
  911.  
  912. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  913. ;              |                          |
  914. ;              |        modify INT 20 into INT 27 in the     |
  915. ;              |        program segment prefix         |
  916. ;              |                          |
  917. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  918.  
  919.       MOV      BYTE PTR ES:[01],27h ; Change INT 20h to INT 27h
  920.  
  921. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  922. ;              |                          |
  923. ;              |     6) load address of ending tag into DX     |
  924. ;              |                          |
  925. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  926.  
  927.       MOV      AX,SEG LASTADDR
  928.       SUB      AX,SEG PRSLASHO
  929.       MOV      CL,4               ; prepare for 4 bit shift
  930.       SHL      AX,CL            ; shift up (convert from seg to abs)
  931.       ADD      AX,OFFSET LASTADDR   ; add address of bottom location
  932.       ADD      AX,0103h           ; Pad offset because DOS measures
  933. ;                      offset relative to Program
  934. ;                      Segment Prefix
  935.       MOV      DX,AX            ; leave where DOS will find it
  936.  
  937. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  938. ;              |                          |
  939. ;              |     7) use RET FAR to return to DOS and     |
  940. ;              |        leave service routine resident     |
  941. ;              |                          |
  942. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  943.  
  944. ALREADY_DONE:
  945.  
  946.       RET
  947.  
  948. PRSLASHO  ENDP
  949.  
  950. SCRDSEG   ENDS
  951.  
  952. ;______________________________________________________________________________
  953.  
  954. STACK      SEGMENT PARA STACK 'STACK'
  955.       DB      24 DUP('STACK***')
  956. TOPSTACK  DB      0
  957. STACK      ENDS
  958.  
  959.       END      PRSLASHO
  960.